home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / dskut / dtst20.zip / DTST.C < prev    next >
C/C++ Source or Header  |  1990-05-01  |  14KB  |  478 lines

  1.  
  2. /*
  3.  * DTST - Special disk test - finds slow sectors
  4.  *
  5.  * Copyright 1988-1990 Samuel H. Smith; All rights reserved.
  6.  *
  7.  * Written 13-feb-88 (rev. 01-may-90)
  8.  *
  9.  */
  10.  
  11. #define VERSION  "DiskTest v2.0 (5-01-90)   Copyright 1988-1990 S.H.Smith"
  12.  
  13. #include <bios.h>
  14. #include <ctype.h>
  15. #include <dos.h>
  16. #include <process.h>
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20.  
  21. #include "abs4read.h"
  22.  
  23. #define SECSIZ   512
  24. #define NSECT    31
  25. char *secbuf;
  26. char *patbuf;
  27.  
  28. #define DIRPERSEC 16            /* directory entries per sector */
  29.  
  30.  
  31. struct bootrec {        /* found at logical sector 0 (absolute read) */
  32.     char jmp[3];
  33.     char oem[8];
  34.     int SectSiz;        /* bytes per sector */
  35.     char ClustSiz;        /* sectors per cluster */
  36.     int ResSecs;        /* reserved sectors before first FAT */
  37.     char FatCnt;        /* number of FATs */
  38.     int RootSiz;        /* max root directory entries (32 bytes each) */
  39.         unsigned sTotSecs;      /* total number or sectors in small partition */
  40.     char Media;        /* media descriptor */
  41.     int FatSize;        /* sectors per fat */
  42.     int TrkSecs;        /* sectors per track */
  43.     int HeadCnt;        /* number of heads */
  44.         long HidnSec;           /* hidden sectors */
  45.         long TotSecs;           /* hidden sectors */
  46.  
  47.         char filler[0x200 - 0x24];
  48. } bootrec;
  49.  
  50.  
  51. #define MAXBAD 2000
  52. unsigned badclusts[MAXBAD];
  53. unsigned badcount = 0;
  54.  
  55. unsigned reserved_sec;
  56. unsigned cyl_secs;
  57.  
  58. #define BADCLUST 0xFFF7
  59. #define FATS_PER_FATSEC (SECSIZ / sizeof(unsigned))
  60. unsigned fatbuf[FATS_PER_FATSEC];
  61.  
  62. int ptrack = -1;
  63. int maxtime = 30;   /* maximum number of ticks for a good read */
  64. unsigned cluster;
  65. int track;
  66.  
  67. int slows = 0;
  68. int new_bad = 0;
  69. int write_check = 0;
  70.  
  71.  
  72. /* --------------------------------------------------------------- */
  73. char *report_error(char result)
  74. {
  75.         switch (result+0x13) {
  76.                 case 0x13:      return "Write protect";
  77.                 case 0x14:      return "Unknown unit";
  78.                 case 0x15:      return "Not ready";
  79.                 case 0x16:      return "Unknown command";
  80.                 case 0x17:      return "Data error";
  81.                 case 0x18:      return "Bad request";
  82.                 case 0x19:      return "Seek error";
  83.                 case 0x1a:      return "Unknown media";
  84.                 case 0x1b:      return "Sector not found";
  85.                 case 0x1d:      return "Write fault";
  86.                 case 0x1e:      return "Read fault";
  87.                 case 0x1f:      return "General failure";
  88.                 case 0x20:      return "Share violation";
  89.                 case 0x21:      return "Lock violation";
  90.                 case 0x22:      return "Bad disk change";
  91.  
  92.                 default:
  93.                         {
  94.                                 static char message[80];
  95.                                 sprintf(message,"Error %02x",result);
  96.                                 return message;
  97.                         }
  98.         }
  99. }
  100.  
  101.  
  102.  
  103. /* --------------------------------------------------------------- */
  104. unsigned sec2clust(long secnum)
  105. {
  106.         if (secnum < reserved_sec)
  107.                 return 0;
  108.     else
  109.                 return 2 + (secnum - (long)reserved_sec) /
  110.                                   (long)bootrec.ClustSiz;
  111. }
  112.  
  113. /* --------------------------------------------------------------- */
  114. long clust2sec(unsigned clust)
  115. {
  116.          return (long)(clust - 2) * (long)bootrec.ClustSiz + (long)reserved_sec;
  117. }
  118.  
  119.  
  120. /* --------------------------------------------------------------- */
  121. void generate_pattern(void)
  122. {
  123.     int i;
  124.  
  125.     srand(biostime(0, 0L));
  126.  
  127.     for (i = 0; i < sizeof(patbuf); i++)
  128.         patbuf[i] = rand();
  129. }
  130.  
  131.  
  132. /* --------------------------------------------------------------- */
  133. int exclude_bad_blocks(unsigned cluster, int track)
  134. {
  135.     int i;
  136.  
  137.     for (i = 0; i < badcount; i++) {
  138.         if (badclusts[i] == cluster) {
  139.             printf("\r  Track %d, cluster %u - Already marked bad\n",
  140.                    track, cluster);
  141.             return 1;
  142.         }
  143.     }
  144.  
  145.     return 0;
  146. }
  147.  
  148.  
  149. /* --------------------------------------------------------------- */
  150. void report_cluster_number(FILE *fd, long secnum, int seccnt, unsigned speed)
  151. {
  152.         if (secnum < reserved_sec)
  153.                  fprintf(fd,"\r  Track %d, sector %u, speed %u mS ",
  154.                          track, secnum, speed);
  155.  
  156.         else if (seccnt > bootrec.ClustSiz)
  157.                 fprintf(fd,"\r  Track %d, clusters %u-%u, speed %u mS ",
  158.                        track,
  159.                        (unsigned)cluster,
  160.                        (unsigned)(cluster + (seccnt / bootrec.ClustSiz) - 1),
  161.                        speed);
  162.     else
  163.                 fprintf(fd,"\r  Track %d, cluster %u, speed %u mS ",
  164.                track, cluster, speed);
  165. }
  166.  
  167.  
  168. /* --------------------------------------------------------------- */
  169. void rewrite_block(char disk, long secnum, int seccnt)
  170.  /* perform a READ/WRITE/READ/ReWRITE test */
  171. {
  172.         char result;
  173.  
  174.         result = abs4write(disk - 'A', seccnt, secnum, patbuf);
  175.     if (result)
  176.                 printf("- PATTERN WRITE FAILED! [%s]\n",report_error(result));
  177.  
  178.         result = abs4read(disk - 'A', seccnt, secnum, patbuf);
  179.     if (result)
  180.                 printf("- PATTERN READ FAILED! [%s]\n",report_error(result));
  181.  
  182.     /* replace original data */
  183.         result = abs4write(disk - 'A', seccnt, secnum, secbuf);
  184.     if (result) {
  185.                 printf("- ORIGINAL RE-WRITE FAILED! [%s]\n\n",report_error(result));
  186.  
  187.                 result = abs4write(disk - 'A', seccnt, secnum, secbuf);
  188.         if (result) {
  189.                         printf("- SECOND RE-WRITE FAILED! [%s]\n\n",report_error(result));
  190.             printf("PROGRAM ABORTED - POSSIBLE DATA LOSS!\n");
  191.             exit(1);
  192.         }
  193.     }
  194. }
  195.  
  196.  
  197. /* --------------------------------------------------------------- */
  198. unsigned check_block(char disk, long secnum, int seccnt)
  199.  /* test a sector/block, return elapsed time for read.  time < 0 on errors */
  200. {
  201.         char result;
  202.     long start;
  203.     int elapsed;
  204.     unsigned speed;
  205.  
  206.         cluster = sec2clust(secnum);
  207.         track = secnum / cyl_secs;
  208.  
  209. /*
  210. printf("\rcheckblock:\tseccnt=%d(@%04x:%04x) secnum=%ld buf=%04x:%04x\n ",
  211.                 seccnt,FP_SEG(&seccnt),FP_OFF(&seccnt),
  212.                 secnum,
  213.                 FP_SEG(secbuf),FP_OFF(secbuf));
  214. */
  215.         if (seccnt > bootrec.ClustSiz)
  216.                 if (exclude_bad_blocks(cluster, track))
  217.                         return 0;
  218.  
  219.     start = biostime(0, 0L);
  220.         result = abs4read(disk - 'A', seccnt, secnum, secbuf);
  221.     elapsed = biostime(0, start) - start;
  222.     speed = elapsed * 18;
  223.  
  224.         if ((elapsed > maxtime) || (result)) {
  225.         ptrack = track;
  226.                 report_cluster_number(stdout, secnum, seccnt, speed);
  227.         } else
  228.  
  229.         /* send non-error status to stderr so it won't clutter logfiles */
  230.         if (track != ptrack) {
  231.         ptrack = track;
  232.                 report_cluster_number(stderr, secnum, seccnt, speed);
  233.     }
  234.  
  235.  
  236.     /* extablish max time for read based on SECOND read request */
  237. /********
  238.         if (maxtime == 999)
  239.         maxtime = 888;
  240.     else if (maxtime == 888)
  241.         maxtime = (elapsed + 1) * 3;
  242. *******/
  243.  
  244.     /* report errors or slow reads */
  245.     if (result) {
  246.                 printf("- HARD ERROR! [%s]\n",report_error(result));
  247.                 if (seccnt <= bootrec.ClustSiz)
  248.             new_bad++;
  249.     }
  250.     else if (elapsed > maxtime) {
  251.         printf("- SLOW! (soft errors)\n");
  252.         slows++;
  253.         result = 999;
  254.     }
  255.  
  256.     if ((result == 0) && write_check)
  257.                 rewrite_block(disk, secnum, seccnt);
  258.  
  259.     if (result)
  260.         return -elapsed;
  261.     else
  262.         return elapsed;
  263. }
  264.  
  265.  
  266. /* --------------------------------------------------------------- */
  267. void test_range(char disk, long low, long last)
  268. {
  269.         long current;
  270.         long single;
  271.     int elapsed;
  272.     int nsect;
  273.  
  274.     if (write_check)
  275.         printf("\nPerforming READ/WRITE test:\n");
  276.     else
  277.         printf("\nPerforming READ test:\n");
  278.  
  279.     nsect = bootrec.TrkSecs;
  280.     if (nsect > NSECT)
  281.         nsect = NSECT;    /* special case for large-track disks
  282.                  * (bernouli) */
  283.  
  284.     for (current = low; current <= last - nsect + 1; current += nsect) {
  285.  
  286. /*
  287. printf("\rrange(1):\t nsect=%d(@%04x:%04x) curr